use crate::parts::{CleanTarget, MavenPom, MavenTargetType, ProjectType};
use colored::Colorize;
use humansize::{DECIMAL, format_size};
use indicatif::{ProgressBar, ProgressStyle};
use rayon::iter::{Either, IntoParallelRefIterator, ParallelIterator};
use rayon::prelude::ParallelBridge;
use std::{
    io::Write,
    path::{Path, PathBuf},
    fs,
};
use walkdir::WalkDir;

/// 扫描给定目录，查找所有符合条件的待清理目录
pub fn scan_path(root_path: &Path) -> anyhow::Result<Vec<CleanTarget>> {
    let spinner = ProgressBar::new_spinner();
    let spinner_style = ProgressStyle::default_spinner();
    let spinner_templated = spinner_style.template("{spinner:.blue} {msg}");
    spinner.set_style(spinner_templated?);
    spinner.set_message("Scanning directories...");
    spinner.enable_steady_tick(std::time::Duration::from_millis(100));

    let mut found_projects = Vec::new();
    let mut walker = WalkDir::new(root_path).into_iter();

    while let Some(Ok(entry)) = walker.next() {
        if !entry.file_type().is_dir() {
            continue;
        }

        let dir_path = entry.path();
        spinner.set_message(format!("Scanning: {}", dir_path.display()));

        // 检查是否是 Rust 项目
        if dir_path.join(ProjectType::Cargo.tag()).exists() {
            if let Some(target) = handle_rust_project(dir_path) {
                found_projects.push(target);
            }
            // 剪枝：不再深入扫描这个项目内部
            walker.skip_current_dir();
            continue;
        }

        // --- Maven 项目处理 ---
        if dir_path.join(ProjectType::Maven.tag()).exists() {
            match handle_maven_project(dir_path, &spinner) {
                Ok(maven_targets) => {
                    found_projects.extend(maven_targets);
                }
                Err(e) => {
                    // 解析失败时打印警告，但程序不崩溃
                    eprintln!(
                        "{} Could not parse pom.xml in '{}': {}",
                        "WARN".yellow(),
                        dir_path.display(),
                        e
                    );
                }
            }
            // 剪枝：无论成功与否，Maven项目已被处理，不再盲目深入
            walker.skip_current_dir();
        }
    }

    spinner.finish_with_message("Scan complete.");
    Ok(found_projects)
}

/// 处理 Rust 项目
fn handle_rust_project(path: &Path) -> Option<CleanTarget> {
    let target_dir = path.join(MavenTargetType::Target.to_string());
    if target_dir.exists() && target_dir.is_dir() {
        println!("{} Found Rust target in: {}", "->".cyan(), path.display());
        let size = calculate_dir_size(&target_dir);
        return Some(CleanTarget {
            path: target_dir,
            project_type: ProjectType::Cargo,
            size_bytes: size,
        });
    }
    None
}

/// 核心逻辑：处理一个找到的 Maven 项目
fn handle_maven_project(
    project_path: &Path,
    spinner: &ProgressBar,
) -> anyhow::Result<Vec<CleanTarget>> {
    let pom_path = project_path.join(ProjectType::Maven.tag());
    spinner.set_message(format!("Parsing {}", pom_path.display()));

    let xml_content = fs::read_to_string(&pom_path)?;
    let pom: MavenPom = quick_xml::de::from_str(&xml_content)?;

    let mut targets_in_project = Vec::new();

    // 不管是否是多模块项目，都会在检测是pom.xml存在的那个层级，尝试寻找target/build文件
    if let Some(target) = find_target_or_build_for_maven(project_path) {
        targets_in_project.push(target);
    }
    // 然后再判断是否多模块项目
    if pom.modules.module.is_empty() {
        // --- 情况一：单模块项目 --- 打印即可
        spinner.set_message(format!(
            "Found single-module Maven project: {}",
            project_path.display()
        ));
    } else {
        // --- 情况二：多模块（父）项目 --- 往下查找
        spinner.set_message(format!(
            "Found multi-module Maven project: {}",
            project_path.display()
        ));
        for module_name in &pom.modules.module {
            let module_path = project_path.join(module_name);
            if module_path.is_dir() {
                // 在每个声明的模块子目录中寻找 target/build
                if let Some(target) = find_target_or_build_for_maven(&module_path) {
                    targets_in_project.push(target);
                }
            }
        }
    }

    Ok(targets_in_project)
}

/// 处理单个 Maven 模块 (如果找到target就终止，找不到就找build)
fn find_target_or_build_for_maven(path: &Path) -> Option<CleanTarget> {
    let target_dir = path.join(MavenTargetType::Target.to_string());
    if target_dir.exists() && target_dir.is_dir() {
        return maven_target(MavenTargetType::Target, path, target_dir);
    }
    let build_dir = path.join(MavenTargetType::Build.to_string());
    if build_dir.exists() && build_dir.is_dir() {
        return maven_target(MavenTargetType::Build, path, build_dir);
    }
    None
}

fn maven_target(maven_type: MavenTargetType, path: &Path, dir: PathBuf) -> Option<CleanTarget> {
    println!(
        "{} Found Maven {} in: {}",
        "->".cyan(),
        maven_type.to_string(),
        path.display()
    );
    let size = calculate_dir_size(&dir);
    Some(CleanTarget {
        path: dir,
        project_type: ProjectType::Maven,
        size_bytes: size,
    })
}

/// 并发计算目录大小
fn calculate_dir_size(path: &Path) -> u64 {
    WalkDir::new(path)
        .into_iter()
        .filter_map(|e| e.ok())
        .filter(|e| e.file_type().is_file())
        .par_bridge() // 切换到并发处理
        .map(|entry| entry.metadata().map(|m| m.len()).unwrap_or(0))
        .sum()
}

/// 打印找到的目标和总结
pub fn display_report(targets: &[CleanTarget]) {
    println!("\n--- Scan Report ---");
    let mut total_size = 0;
    for target in targets {
        total_size += target.size_bytes;
        println!(
            "  - [{:?}] {} ({})",
            target.project_type,
            target.path.display(),
            format_size(target.size_bytes, DECIMAL).yellow()
        );
    }
    println!("--------------------");
    println!(
        "{} Found {} clean targets (maven or cargo), total size: {}",
        "SUMMARY".bold(),
        targets.len(),
        format_size(total_size, DECIMAL).red().bold()
    );
}

/// 提示用户确认删除
pub fn confirm_deletion() -> anyhow::Result<bool> {
    print!(
        "{} This action is irreversible. Are you sure you want to delete these directories? (y/n): ",
        "WARNING:".red().bold()
    );
    std::io::stdout().flush()?;

    let mut confirmation = String::new();
    std::io::stdin().read_line(&mut confirmation)?;

    Ok(confirmation.trim().eq_ignore_ascii_case("y"))
}

pub fn delete_targets(targets: &[CleanTarget]) {
    println!("\n{}", "--- Deleting Directories ---".bold());
    let pb = ProgressBar::new(targets.len() as u64);
    pb.set_style(
        ProgressStyle::default_bar()
            .template("{bar:40.cyan/blue} {pos}/{len} {msg}")
            .unwrap()
            .progress_chars("##-"),
    );

    // --- 2. 使用 partition_map 进行替换 ---
    let (successes, failures): (Vec<&CleanTarget>, Vec<(&CleanTarget, std::io::Error)>) = targets
        .par_iter() // 并发删除
        .partition_map(|target| {
            pb.set_message(format!("Deleting {}...", target.path.display()));
            match fs::remove_dir_all(&target.path) {
                Ok(_) => {
                    pb.inc(1);
                    // 成功，放入左边的集合
                    Either::Left(target)
                }
                Err(e) => {
                    // 失败，将目标和错误一起放入右边的集合
                    Either::Right((target, e))
                }
            }
        });

    pb.finish_with_message("Deletion complete.");

    // 3. 统计共删除的文件大小
    let total_deleted_size: u64 = successes.iter().map(|t| t.size_bytes).sum();

    println!(
        "{}",
        format!(
            "Successfully deleted {} directories, freeing up {}.",
            successes.len(),
            format_size(total_deleted_size, DECIMAL)
        )
        .green()
    );

    if !failures.is_empty() {
        println!(
            "{}",
            format!("Failed to delete {} directories:", failures.len()).red()
        );
        // failures 现在直接是 (target, error) 的元组，非常方便
        for (target, error) in failures {
            println!("  - {}: {}", target.path.display(), error);
        }
    }
}
